package com.yanqu.road.server.manger.activity.operamask;

import com.yanqu.road.entity.activity.operamask.OperaMaskConfig;
import com.yanqu.road.entity.activity.operamask.game.OperaMaskBlock;
import com.yanqu.road.entity.activity.operamask.game.OperaMaskSkill;
import com.yanqu.road.entity.activity.operamask.sanxiao.OperaMaskCalcBombPosResult;
import com.yanqu.road.entity.activity.operamask.sanxiao.OperaMaskShapeMatchResult;
import com.yanqu.road.entity.activity.operamask.sanxiao.OperaMaskSkillEffect;
import com.yanqu.road.entity.enums.eOperaMaskBlockType;
import com.yanqu.road.entity.enums.eOperaMaskSkillType;
import com.yanqu.road.utils.RandomHelper;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Random;
import java.util.Set;

public class OperaMaskCreateBombLogic {

    private static RandomHelper randomHelper = new RandomHelper();

    /**
     * 获取生成的炸弹
     */
    public static List<OperaMaskBlock> getCreateBombList(List<OperaMaskSkill> skillList,
                                                         int round, int fromX, int fromY, int toX, int toY,
                                                         Set<OperaMaskBlock> eliminateSet,
                                                         Set<OperaMaskBlock> dropSet,
                                                         Random random, OperaMaskConfig config,
                                                         List<OperaMaskSkillEffect> effectList,
                                                         int sceneId) {
        List<OperaMaskBlock> addBombList = new ArrayList<>();

        boolean canObliqueEliminate = OperaMaskSkillLogic.getSkill08Effect(skillList);

        // 分组
        Map<Integer, List<List<OperaMaskBlock>>> listListMap = groupEliminateSet(eliminateSet, canObliqueEliminate);

        OperaMaskSkillEffect effect = new OperaMaskSkillEffect(eOperaMaskSkillType.Skill99.getValue());
        int skill99Effect = OperaMaskSkillLogic.getSkill99Effect(skillList, config);
        // 长坂坡剧目效果,移动消除不生成炸弹
        List<Integer> sceneEffect1005 = OperaMaskSkillLogic.getSceneSkillEffectList(config.getSceneConfigMap().get(sceneId), eOperaMaskSkillType.Skill1005);
        // 遍历生成炸弹
        for (List<List<OperaMaskBlock>> listList : listListMap.values()) {
            for (int i = 0; i < listList.size(); i++) {
                List<OperaMaskBlock> list = listList.get(i);
                // 匹配形状
                OperaMaskShapeMatchResult result = OperaMaskShapeLogic.matchShape(list, 1);
                if (result != null && sceneEffect1005 == null) {
                    // 生成炸弹  长坂坡剧目效果,移动消除不生成炸弹
                    OperaMaskBlock bombBlock = createBombBlock(result, round, fromX, fromY, toX, toY, dropSet, random);
                    addBombList.add(bombBlock);
                    // 剩余格子继续生成炸弹
                    list.removeAll(result.getUseBlockList());
                    if (!list.isEmpty()) {
                        i--;
                    }
                } else if (skill99Effect > 0) {
                    result = OperaMaskShapeLogic.matchShape(list, 2);
                    if (result != null && random.nextInt(1000) < skill99Effect) {
                        // 技能99生成炸弹
                        OperaMaskBlock block = createSkill99BombBlock(list, round, fromX, fromY, toX, toY, dropSet, random);
                        addBombList.add(block);
                        effect.getBlockList().add(block);
                    }
                }
            }
        }

        // 加技能特效
        if (effect.getBlockList().size() > 0) {
            effectList.add(effect);
        }

        return addBombList;
    }

    /**
     * 生成炸弹格子
     */
    public static OperaMaskBlock createBombBlock(OperaMaskShapeMatchResult result,
                                                 int round, int fromX, int fromY, int toX, int toY,
                                                 Set<OperaMaskBlock> dropSet, Random random) {
        // 【找生成炸弹的位置】
        OperaMaskCalcBombPosResult bombPosResult = calcCreateBombPos(result.getUseBlockList(), round, fromX, fromY, toX, toY, dropSet);

        // 【计算炸弹类型】
        eOperaMaskBlockType bombType = null;
        int needCount = result.getShapeConfig().getNeedCount();
        eOperaMaskBlockType appointBombType = result.getShapeConfig().getShapeType().getAppointBombType();

        if (appointBombType != null) { // 【形状有指定类型】
            bombType = appointBombType;
        } else if (needCount == 4 && bombPosResult.isContainsMoveBlock()) { // 【移动方向指定类型】
            if (fromX != toX && fromY != toY) {
                bombType = random.nextInt(1000) > 500 ? eOperaMaskBlockType.BombShu : eOperaMaskBlockType.BombHeng; // 斜向交换
            } else {
                bombType = fromX == toX ? eOperaMaskBlockType.BombShu : eOperaMaskBlockType.BombHeng; // 横/竖交换
            }
        }

        // 正常情况：看消耗的方块数量
        if (bombType == null) {
            if (needCount == 4) {
                bombType = randomHelper.next(2) >= 1 ? eOperaMaskBlockType.BombHeng : eOperaMaskBlockType.BombShu;
            } else if (needCount >= 5) {
                bombType = eOperaMaskBlockType.BombColorful;
            }
        }

        if (bombType == null) {
            bombType = eOperaMaskBlockType.NormalBlock;
        }

        // 生成炸弹格子
        OperaMaskBlock clone = bombPosResult.getPosBlock().cloneNoMulti();
        clone.setType(bombType.getValue());
        if (bombType == eOperaMaskBlockType.BombColorful || bombType == eOperaMaskBlockType.BombSuperColorful) {
            clone.setColor(0);
        }
        return clone;
    }

    /**
     * 计算炸弹生成位置
     */
    private static OperaMaskCalcBombPosResult calcCreateBombPos(List<OperaMaskBlock> useBlock,
                                                                int round, int fromX, int fromY, int toX, int toY,
                                                                Set<OperaMaskBlock> dropSet) {
        // 第一轮 && 包含交换的格子
        boolean firstRound = round == 1;
        if (firstRound) {
            Optional<OperaMaskBlock> any = useBlock.stream().filter(item -> item.getX() == toX && item.getY() == toY).findAny();
            if (any.isPresent()) {
                return new OperaMaskCalcBombPosResult(any.get(), true);
            }
            any = useBlock.stream().filter(item -> item.getX() == fromX && item.getY() == fromY).findAny();
            if (any.isPresent()) {
                return new OperaMaskCalcBombPosResult(any.get(), true);
            }
        }

        // 包含掉落格子（useBlock是小到大排序的）
        for (OperaMaskBlock block : useBlock) {
            if (dropSet.contains(block)) {
                return new OperaMaskCalcBombPosResult(block, false);
            }
        }

        return new OperaMaskCalcBombPosResult(useBlock.get(0), false);
    }

    /**
     * 消除的方块按颜色、相邻分组
     */
    public static Map<Integer, List<List<OperaMaskBlock>>> groupEliminateSet(Set<OperaMaskBlock> eliminateSet, boolean canObliqueEliminate) {
        Map<Integer, List<List<OperaMaskBlock>>> listListMap = new HashMap<>();

        for (OperaMaskBlock block : eliminateSet) {
            // 跳过没颜色的
            if (block.getColor() == 0) {
                continue;
            }

            listListMap.putIfAbsent(block.getColor(), new ArrayList<>());
            List<List<OperaMaskBlock>> listList = listListMap.get(block.getColor());

            // 和该方块相邻的方块位于list的哪些下标
            List<Integer> adjoinIndexList = new ArrayList<>();
            for (int i = 0; i < listList.size(); i++) {
                List<OperaMaskBlock> list = listList.get(i);
                for (OperaMaskBlock tmpBlock : list) {
                    if (tmpBlock.getColor() == block.getColor() && isBlockAdjoin(tmpBlock, block, canObliqueEliminate)) {
                        adjoinIndexList.add(i);
                        break;
                    }
                }
            }

            // 相邻的合并起来
            List<OperaMaskBlock> list = new ArrayList<>();
            list.add(block);
            for (Integer index : adjoinIndexList) {
                list.addAll(listList.get(index));
            }
            for (int i = adjoinIndexList.size() - 1; i >= 0; i--) {
                listList.remove((int) adjoinIndexList.get(i));
            }
            listList.add(list);
        }

        // 排个序吧，按位置小到大
        for (List<List<OperaMaskBlock>> listList : listListMap.values()) {
            for (List<OperaMaskBlock> list : listList) {
                list.sort(new Comparator<OperaMaskBlock>() {
                    @Override
                    public int compare(OperaMaskBlock o1, OperaMaskBlock o2) {
                        if (o1.getY() != o2.getY()) {
                            return o1.getY() - o2.getY();
                        } else if (o1.getX() != o2.getX()) {
                            return o1.getX() - o2.getX();
                        } else {
                            return 0;
                        }
                    }
                });
            }
        }

        return listListMap;
    }

    /**
     * 方块是否相邻（可斜消时斜着的也算相邻）
     */
    private static boolean isBlockAdjoin(OperaMaskBlock block1, OperaMaskBlock block2, boolean canObliqueEliminate) {
        int subY = Math.abs(block1.getY() - block2.getY());
        int subX = Math.abs(block1.getX() - block2.getX());

        // 超过1必定不相邻
        if (subX > 1 || subY > 1) {
            return false;
        }

        int sum = subX + subY;
        int limit = canObliqueEliminate ? 2 : 1; // 斜向左右距离差得和是1
        return sum <= limit;
    }


    public static OperaMaskBlock createSkill99BombBlock(List<OperaMaskBlock> blockList,
                                                        int round, int fromX, int fromY, int toX, int toY,
                                                        Set<OperaMaskBlock> dropSet, Random random) {
        // 【找生成炸弹的位置】
        OperaMaskCalcBombPosResult bombPosResult = calcCreateBombPos(blockList, round, fromX, fromY, toX, toY, dropSet);

        // 【计算炸弹类型】
        eOperaMaskBlockType bombType = random.nextInt(1000) < 500 ? eOperaMaskBlockType.BombHeng : eOperaMaskBlockType.BombShu;

        // 生成炸弹格子
        OperaMaskBlock clone = bombPosResult.getPosBlock().cloneNoMulti();
        clone.setType(bombType.getValue());
        return clone;
    }

}
